#ifndef HASHMAP_IMPL_H_
#define HASHMAP_IMPL_H_
#include "hashset_impl.h"
#define IMPL_QUAL_PAIR_EQ_BY_KEY(KTYPE, VTYPE, EQ, QUAL) \
  QUAL int EQ##_ctl_pair_##KTYPE##_##VTYPE(const ctl_pair_##KTYPE##_##VTYPE lhs, const ctl_pair_##KTYPE##_##VTYPE rhs) {\
    return EQ##_##KTYPE(lhs.first, rhs.first); \
  }

#define IMPL_QUAL_PAIR_HASH_BY_KEY(KTYPE, VTYPE, HASH, QUAL) \
  QUAL size_t HASH##_ctl_pair_##KTYPE##_##VTYPE(const ctl_pair_##KTYPE##_##VTYPE lhs) {\
    return HASH##_##KTYPE(lhs.first); \
  }

#define IMPL_QUAL_METH_HASHMAP(KTYPE, VTYPE, HASH, EQ, QUAL, METH, RET, ...) \
  RET ctl_hashmap_##KTYPE##_##VTYPE##_##HASH##_##EQ##_##METH(ctl_hashmap_##KTYPE##_##VTYPE##_##HASH##_##EQ* ht) { \
    return ctl_hashset_ctl_pair_##KTYPE##_##VTYPE##_##HASH##_##EQ##_##METH(ht); \
  }

#define IMPL_QUAL_HASHMAP(KTYPE, VTYPE, HASH, EQ, QUAL) \
  IMPL_QUAL_PAIR_EQ_BY_KEY(KTYPE, VTYPE, EQ, QUAL) \
  IMPL_QUAL_PAIR_HASH_BY_KEY(KTYPE, VTYPE, HASH, QUAL) \
  IMPL_QUAL_HASHSET(ctl_pair_##KTYPE##_##VTYPE, HASH, EQ, QUAL) \
  QUAL ctl_res_ctl_pair_##KTYPE##_##VTYPE ctl_hashmap_##KTYPE##_##VTYPE##_##HASH##_##EQ##_iter_data(ctl_hashmap_##KTYPE##_##VTYPE##_##HASH##_##EQ##_iter iter) { \
    return ctl_hashset_ctl_pair_##KTYPE##_##VTYPE##_##HASH##_##EQ##_iter_data(iter); \
  } \
  QUAL ctl_res_ctl_hashmap_##KTYPE##_##VTYPE##_##HASH##_##EQ##_iter ctl_hashmap_##KTYPE##_##VTYPE##_##HASH##_##EQ##_iter_next(ctl_hashmap_##KTYPE##_##VTYPE##_##HASH##_##EQ##_iter iter) { \
    return ctl_hashset_ctl_pair_##KTYPE##_##VTYPE##_##HASH##_##EQ##_iter_next(iter); \
  } \
  QUAL ctl_res_ctl_hashmap_##KTYPE##_##VTYPE##_##HASH##_##EQ##_iter ctl_hashmap_##KTYPE##_##VTYPE##_##HASH##_##EQ##_begin(ctl_hashmap_##KTYPE##_##VTYPE##_##HASH##_##EQ* ht) { \
    return ctl_hashset_ctl_pair_##KTYPE##_##VTYPE##_##HASH##_##EQ##_begin(ht); \
  } \
  QUAL size_t ctl_hashmap_##KTYPE##_##VTYPE##_##HASH##_##EQ##_size(ctl_hashmap_##KTYPE##_##VTYPE##_##HASH##_##EQ* ht) { \
    return ctl_hashset_ctl_pair_##KTYPE##_##VTYPE##_##HASH##_##EQ##_size(ht);  \
  } \
  QUAL ctl_res_void ctl_hashmap_##KTYPE##_##VTYPE##_##HASH##_##EQ##_ctor_with_capacity(ctl_hashmap_##KTYPE##_##VTYPE##_##HASH##_##EQ* ht, size_t capacity) { \
    return ctl_hashset_ctl_pair_##KTYPE##_##VTYPE##_##HASH##_##EQ##_ctor_with_capacity(ht, capacity);  \
  } \
  QUAL ctl_res_ctl_hashmap_##KTYPE##_##VTYPE##_##HASH##_##EQ##_p ctl_hashmap_##KTYPE##_##VTYPE##_##HASH##_##EQ##_new_with_capacity(size_t capacity) { \
    return ctl_hashset_ctl_pair_##KTYPE##_##VTYPE##_##HASH##_##EQ##_new_with_capacity(capacity);  \
  } \
  QUAL ctl_res_void ctl_hashmap_##KTYPE##_##VTYPE##_##HASH##_##EQ##_ctor(ctl_hashmap_##KTYPE##_##VTYPE##_##HASH##_##EQ* ht) { \
    return ctl_hashset_ctl_pair_##KTYPE##_##VTYPE##_##HASH##_##EQ##_ctor(ht); \
  } \
  QUAL ctl_res_ctl_hashmap_##KTYPE##_##VTYPE##_##HASH##_##EQ##_p ctl_hashmap_##KTYPE##_##VTYPE##_##HASH##_##EQ##_new() { \
    return ctl_hashset_ctl_pair_##KTYPE##_##VTYPE##_##HASH##_##EQ##_new(); \
  } \
  QUAL ctl_res_void ctl_hashmap_##KTYPE##_##VTYPE##_##HASH##_##EQ##_dtor(ctl_hashmap_##KTYPE##_##VTYPE##_##HASH##_##EQ* ht) { \
    return ctl_hashset_ctl_pair_##KTYPE##_##VTYPE##_##HASH##_##EQ##_dtor(ht); \
  } \
  QUAL ctl_res_void ctl_hashmap_##KTYPE##_##VTYPE##_##HASH##_##EQ##_free(ctl_hashmap_##KTYPE##_##VTYPE##_##HASH##_##EQ* ht) { \
    return ctl_hashset_ctl_pair_##KTYPE##_##VTYPE##_##HASH##_##EQ##_free(ht); \
  } \
  QUAL ctl_res_void ctl_hashmap_##KTYPE##_##VTYPE##_##HASH##_##EQ##_copy(ctl_hashmap_##KTYPE##_##VTYPE##_##HASH##_##EQ* dst, ctl_hashmap_##KTYPE##_##VTYPE##_##HASH##_##EQ* src) { \
    return ctl_hashset_ctl_pair_##KTYPE##_##VTYPE##_##HASH##_##EQ##_copy(dst, src); \
  } \
  QUAL ctl_res_ctl_hashmap_##KTYPE##_##VTYPE##_##HASH##_##EQ##_iter ctl_hashmap_##KTYPE##_##VTYPE##_##HASH##_##EQ##_get(const ctl_hashmap_##KTYPE##_##VTYPE##_##HASH##_##EQ* ht, KTYPE key) { \
    ctl_pair_##KTYPE##_##VTYPE pair; \
    ctl_pair_##KTYPE##_##VTYPE##_ctor(&pair); \
    KTYPE##_copy(&(pair.first), &key); \
    return ctl_hashset_ctl_pair_##KTYPE##_##VTYPE##_##HASH##_##EQ##_get(ht, pair); \
  } \
  QUAL ctl_res_void ctl_hashmap_##KTYPE##_##VTYPE##_##HASH##_##EQ##_put(ctl_hashmap_##KTYPE##_##VTYPE##_##HASH##_##EQ* ht, KTYPE key) { \
    ctl_pair_##KTYPE##_##VTYPE pair; \
    ctl_pair_##KTYPE##_##VTYPE##_ctor(&pair); \
    KTYPE##_copy(&(pair.first), &key); \
    return ctl_hashset_ctl_pair_##KTYPE##_##VTYPE##_##HASH##_##EQ##_put(ht, pair); \
  } \
  QUAL ctl_res_void ctl_hashmap_##KTYPE##_##VTYPE##_##HASH##_##EQ##_remove_by_iter(ctl_hashmap_##KTYPE##_##VTYPE##_##HASH##_##EQ* ht, ctl_hashmap_##KTYPE##_##VTYPE##_##HASH##_##EQ##_iter iter) { \
    return ctl_hashset_ctl_pair_##KTYPE##_##VTYPE##_##HASH##_##EQ##_remove_by_iter(ht, iter); \
  } \
  QUAL ctl_res_void ctl_hashmap_##KTYPE##_##VTYPE##_##HASH##_##EQ##_remove(ctl_hashmap_##KTYPE##_##VTYPE##_##HASH##_##EQ* ht, KTYPE key) { \
    ctl_pair_##KTYPE##_##VTYPE pair; \
    ctl_pair_##KTYPE##_##VTYPE##_ctor(&pair); \
    KTYPE##_copy(&(pair.first), &key); \
    return ctl_hashset_ctl_pair_##KTYPE##_##VTYPE##_##HASH##_##EQ##_remove(ht, pair); \
  }

#define IMPL_HASHMAP(KTYPE, VTYPE, HASH, EQ) IMPL_QUAL_HASHMAP(KTYPE, VTYPE, HASH, EQ,) 
#endif